// **********************************************************************
//
// Copyright (c) 2003-2005 ZeroC, Inc. All rights reserved.
//
// This copy of Ice is licensed to you under the terms described in the
// ICE_LICENSE file included in this distribution.
//
// **********************************************************************

#include "TaskManager.h"
//#include "LogWrapper.h"

using namespace MyUtil;

//---------------------------------------------------------------------------
Task::Task(int level) : _level(level)
{
}

Task::~Task()
{

}

int
Task::level()
{
    return _level;
}

void
Task::level(int level)
{
    _level = level;
}
 
//---------------------------------------------------------------------------
TaskHandler::TaskHandler() :
    _activateTime(IceUtil::Time::now()),
    _stopFlag(false)
{
}

TaskHandler::~TaskHandler()
{

}

void
TaskHandler::handle(const TaskPtr& task)
{
    IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this);
    _task = task;
    _activateTime = IceUtil::Time::now();
    notify();
}

void
TaskHandler::stop()
{
    IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this);
    _stopFlag = true;
    notify();
}

IceUtil::Time&
TaskHandler::activateTime()
{
    return _activateTime;
}

void
TaskHandler::run()
{
    while (true) {
        IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this);
        //UNISON_DEBUG("TaskHandler wakes up ... ");
        if (_task) {
            try {
                //UNISON_DEBUG("TaskHandler hindling task ... ");
				_task->handle();
                //UNISON_DEBUG("TaskHandler handling task done.");
            } catch (...) {
                // do nothing
            }
            TaskManager::instance().handlerFinished(this);
            _task = 0;
        } else {
            if (_stopFlag) {
		//delete longMem;
                return;
            }
            try {
                wait();
            } catch (...) {
                // do nothing
            }
        }
    }
}

//---------------------------------------------------------------------------
TaskManager::~TaskManager()
{
    for (TaskHandlerList::iterator it = _busyHandlers.begin();
        it != _busyHandlers.end(); ++it) {
        (*it)->stop();
    }
    _busyHandlers.clear();
    for (TaskHandlerList::iterator it = _idleHandlers.begin();
        it != _idleHandlers.end(); ++it) {
        (*it)->stop();
    }
    _idleHandlers.clear();
}

void
TaskManager::initialize(
    uint32_t minHandlers,
    uint32_t maxHandlers,
    uint32_t threadStackSize,
    uint32_t handlerIdleThreshold)
{
	IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_taskMutex);
	if ((_idleHandlers.size() + _busyHandlers.size()) >= minHandlers) {
		return;
	}
    _minHandlers = minHandlers;
    _maxHandlers = maxHandlers;
    _handlerIdleThreshold = IceUtil::Time::seconds(handlerIdleThreshold);
    _threadStackSize = threadStackSize;
    for ( uint32_t i = 0; i < _minHandlers; ++i) {
        _idleHandlers.push_back(createHandler());
    }
    Thread::start(threadStackSize).detach();
    //UNISON_DEBUG("TaskManager starting TaskManager back thread done.");
}

void
TaskManager::run()
{
    while (true) {
        // Try to pop a task to dispatch in _handlerIdleThreshold secs,
        // if waiting timeout, it will return a NULL Task.
        TaskPtr task = pop();
        if (!task) {
            // ok, timeout try to pinch the idle handlers
            //UNISON_DEBUG("TaskManager got NULL, pinching handlers ... ");
            pinchHandlers();
            continue;
        }
        //UNISON_DEBUG("TaskManager got one task");
        // ok, get a Task
        try {
            //UNISON_DEBUG("TaskManager getIdleHandler, busy handlers: "
                //<< _busyHandlers.size() << ", idle handlers: "
                //<< _idleHandlers.size());
            getIdleHandler()->handle(task);
        } catch (...) {
            // do nothing
        }
    }
}

TaskHandlerPtr
TaskManager::getIdleHandler()
{
    while (true) {
        IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_handlerMutex);
        if (_idleHandlers.size()) {
            TaskHandlerPtr handler = _idleHandlers.back();
            _idleHandlers.pop_back();
            _busyHandlers.push_back(handler);
            //UNISON_DEBUG("TaskManager got a idle handler");
            return handler;
        }
        if (_busyHandlers.size() < _maxHandlers) {
            TaskHandlerPtr handler = createHandler();
            if (handler) {
                _busyHandlers.push_back(handler);
                //UNISON_DEBUG("TaskManager create a handler");
                return handler;
            }
        }
        try {
            //UNISON_DEBUG("TaskManager waits for other busy handlers");
            _handlerMutex.wait();
        } catch (...) {
        }
    }
}

TaskHandlerPtr
TaskManager::createHandler()
{
    TaskHandlerPtr handler = new TaskHandler;
    if (!handler) {
        return 0;
    }
    handler->start(_threadStackSize).detach();
    return handler;
}

void
TaskManager::handlerFinished(const TaskHandlerPtr& handler)
{
    IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_handlerMutex);
    _busyHandlers.remove(handler);
    _idleHandlers.push_back(handler);
    //UNISON_DEBUG( "TaskManager handlerFinished, busy handlers: "
        //<< _busyHandlers.size() << ", idle handlers: "
        //<< _idleHandlers.size() );
    if (_idleHandlers.size() == 1) {
        _handlerMutex.notify();
    }
}

void
TaskManager::push(const TaskPtr& task)
{
    IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_taskMutex);
    //UNISON_DEBUG( "TaskManager push task: "
           // << taskSize()
           // << ", Levels: " << _tasks.size()
           // << ", task level: " << task->level() );
    _tasks[task->level()].push_back(task);
    if (taskSize() == 1) {
        _taskMutex.notify();
    }
}

TaskPtr
TaskManager::pop()
{
    while (true) {
        IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_taskMutex);
        if (!taskSize()) {
            //UNISON_DEBUG("TaskManager got no tasks, try timedWait" );
            try {
                _taskMutex.timedWait(_handlerIdleThreshold);
            } catch (...) {
                continue;
            }
        }
        // Check the number of tasks, if it equals 0, that means waiting
        // is timeout, so we return NULL to break this cycle
        if (!taskSize()) {
            //UNISON_DEBUG("TaskManager waits timeout, return NULL");
            return 0;
        }
        for (TaskMap::reverse_iterator it = _tasks.rbegin();
                it != _tasks.rend(); ++it) {
            if (!it->second.size()) {
                continue;
            }
            TaskPtr task = it->second.front();
            //UNISON_DEBUG("TaskManager pop task: "
                //<< taskSize()
                //<< ", Levels: " << _tasks.size()
                //<< ", task level: " << task->level() );
            it->second.pop_front();
            return task;
        }
    }
}

// Because the size function is private, and will be called by self,
// so, I do not use sychorization symatic to avoid dead lock
size_t
TaskManager::taskSize()
{
    size_t sz = 0;
    for (TaskMap::reverse_iterator it = _tasks.rbegin();
            it != _tasks.rend(); ++it) {
        sz += it->second.size();
    }

    return sz;
}

void
TaskManager::pinchHandlers()
{
    IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_handlerMutex);
    if (taskSize() > _idleHandlers.size()) {
        return;
    }

    TaskHandlerList::iterator it = _idleHandlers.begin();
    for (   uint32_t i = _idleHandlers.size();
            i > (taskSize() > _minHandlers ? taskSize() : _minHandlers); ) {
        while (it != _idleHandlers.end()) {
            TaskHandlerPtr& handler = *it;
            if (handlerIdleTimeout(handler)) {
                // ok, release this timeout handler, and check the
                // waitings size again
                _idleHandlers.erase(it++);
                handler->stop();
                --i;
                //UNISON_DEBUG( "Erase, busy handlers: " << _busyHandlers.size()
                    //<< ", idle handlers: " << _idleHandlers.size() );
                break;
            }
            // well, the handler pointed by it is not timeout,
            // check next handler
            ++it;
        }
        // ok, we have release one handler or all waitings have been checked,
        // recycle or check if reach the waitings' end, if so, break checking.
        if (it == _idleHandlers.end()) {
            break;
        }
    }
}

bool
TaskManager::handlerIdleTimeout(const TaskHandlerPtr& handler)
{
    return (IceUtil::Time::now() - handler->activateTime())
            > _handlerIdleThreshold;
}


